/*
 * dtalk.h
 *
 *  Created on: 2020年4月5日
 *      Author: guyadong
 */

#ifndef DTALK_DTALK_ITEM_H_
#define DTALK_DTALK_ITEM_H_
#include <stdexcept>
#include <string>
#include <memory>
#include <algorithm>
#include <functional>
#include <vector>
#include <map>
#include <set>
#include <list>
#include <iterator>
#include <ctime>
#include <sstream>
#include <type_traits>
#include <uri/uri.hh>
#include <tsl/ordered_map.h>
#include <tsl/ordered_set.h>
#include <common_utilits.h>
#include <string_utils.h>
#include <gf_utility.h>
#include <assert_macros.h>
#include <json_utilits.hpp>
#include <assert.h>
#include <observable.hpp>
#include <sample_log.h>
#include "type_helper.h"
#include "dtalk_exceptions.hpp"
#include "dtalk_common_constant.h"

namespace dtalk{
	/** 使用ordered_json,确保元素插入顺序 */
	using json = nlohmann::ordered_json;
#define __E_ENTRY(p,name) {p##name, #name}

	/** 菜单条目类型 */
	enum ItemType {
		/** 参数类型 */
		DIT_OPTION,
		/** 命令 */
		DIT_CMD,
		/** 菜单*/
		DIT_MENU
	};
	NLOHMANN_JSON_SERIALIZE_ENUM(ItemType, {
		__E_ENTRY(DIT_,OPTION),
		__E_ENTRY(DIT_,CMD),
		__E_ENTRY(DIT_,MENU)
	})
	/** 选项类型 */
	enum OptionType {
		/** 字符串  */
		DOP_STRING,
		/** 整数     */
		DOP_INTEGER,
		/** 浮点数 */
		DOP_FLOAT,
		/** 布尔型 true/false 0/1 */
		DOP_BOOL,
		/** 日期  yyyy-MM-dd HH:mm:ss  */
		DOP_DATE,
		/** url字符串 */
		DOP_URL,
		/** 密码字符串 */
		DOP_PASSWORD,
		/** e-mail地址 */
		DOP_EMAIL,
		/** 手机号码(11位) */
		DOP_MPHONE,
		/** 身份证号(15位、18位数字)，最后一位是校验位，可能为数字或字符X */
		DOP_IDNUM,
		/** base64 格式二进制数据 */
		DOP_BASE64,
		/** (6字节)MAC地址二进制数据,允许用':','-'分隔或不分隔 */
		DOP_MAC,
		/** IP地址二进制数据 */
		DOP_IP,
		/** base64 格式JPEG/BMP/PNG格式图像 */
		DOP_IMAGE,
		/** 多选项{@code (n>0)} */
		DOP_MULTICHECK,
		/** 单选开关{@code (n>1)} */
		DOP_SWITCH
	};
	NLOHMANN_JSON_SERIALIZE_ENUM(OptionType, {
		__E_ENTRY(DOP_,STRING),
		__E_ENTRY(DOP_,INTEGER),
		__E_ENTRY(DOP_,FLOAT),
		__E_ENTRY(DOP_,BOOL),
		__E_ENTRY(DOP_,DATE),
		__E_ENTRY(DOP_,URL),
		__E_ENTRY(DOP_,PASSWORD),
		__E_ENTRY(DOP_,EMAIL),
		__E_ENTRY(DOP_,MPHONE),
		__E_ENTRY(DOP_,IDNUM),
		__E_ENTRY(DOP_,BASE64),
		__E_ENTRY(DOP_,MAC),
		__E_ENTRY(DOP_,IP),
		__E_ENTRY(DOP_,IMAGE),
		__E_ENTRY(DOP_,MULTICHECK),
		__E_ENTRY(DOP_,SWITCH)
	})

	//************************************
	// 返回OptionType对应的字符串匹配正则表达式,如果未定义返回空字符串
	// @param    OptionType optionType
	// @return   const std::string&
	//************************************
	static const std::string& pattern_of(OptionType optionType)
	{
		static std::map<OptionType, std::string> patterns = {
			{ OptionType::DOP_INTEGER ,"^[-+]?\\d{1,10}$" },
			{ OptionType::DOP_FLOAT ,"^[-+]?(\\d*\\.\\d+|\\d+)$" },
			{ OptionType::DOP_BOOL ,"^(true|false|1|0|on|off|yes|no)$" },
			{ OptionType::DOP_URL ,"^(https?|ftp|file)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]$" },
			{ OptionType::DOP_EMAIL ,"^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$" },
			{ OptionType::DOP_MPHONE ,"^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\\d{8}$" },
			{ OptionType::DOP_IDNUM ,"(^\\d{15}$)|(^\\d{18}$)|(^\\d{17}(\\d|X|x)$)" },
			{ OptionType::DOP_MAC ,"^([a-fA-F0-9]{2}[:-]?){5}[a-fA-F0-9]{2}$" },
			{ OptionType::DOP_IP ,"^((?:(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d))$" },
			{ OptionType::DOP_MULTICHECK ,"^[\\s,;:]*((\\d+)[\\s,;:]+(\\d+)?)+$" },
			{ OptionType::DOP_SWITCH ,"^\\s*\\d+\\s*$" }
		};
		const static std::string null_pattern = "";
		return patterns.count(optionType) ? patterns[optionType] : null_pattern;
	}

	#define __J_DEF(name) _jf_##name
	#define __J_NAME(name) #name
	/** 需要JSON序列化的字段 ID 定义 */
	enum JField {
		/** BaseItem std::string 条目名称([a-zA-Z0-9_],不允许有空格) */
		__J_DEF(name),
		/** BaseItem std::string 条目的界面显示名称,如果不指定则使用 name */
		__J_DEF(uiName),
		/** BaseItem std::string 当前对象在整个菜单树形结构中的全路径 */
		__J_DEF(path),
		/** BaseItem bool 当前条目是否禁用 */
		__J_DEF(disable),
		/** BaseItem bool 当前条目是否在UI界面中隐藏 */
		__J_DEF(hide),
		/** BaseItem std::string 对当前条目的说明文字 */
		__J_DEF(description),
		/** BaseItem bool 是否为容器(可包含条目) */
		__J_DEF(container),
		/** BaseItem ItemType 条目分类类型 */
		__J_DEF(catalog),
		/** BaseItem json 所有子条目 */
		__J_DEF(childs),
		/**
		 * CmdItem 取消正在执行的设备命令<br>
		 * 此字段默认为{@code false}或空，为{@code true}时，指示取消正在执行的设备命令,仅对支持交互的设备命令有效
		 */
		__J_DEF(canceled),
		/** BaseOption OptionType 当前选项的类型 */
		__J_DEF(type),
		/** BaseOption 当前选项的值 */
		__J_DEF(value),
		/** BaseOption 当前选项的默认值 */
		__J_DEF(defaultValue),
		/** BaseOption bool  该选项是否为必须的 */
		__J_DEF(required),
		/** BaseOption bool 该选项是否为只读的 */
		__J_DEF(readOnly),
		/** BaseOption bool 修改此选项值时会不会导致应用重启 */
		__J_DEF(needReset),
		/** BaseOption 该选项已知可用的的值 */
		__J_DEF(available),
		/** BaseOption 该选项的字符串合法性检查正则表达式 */
		__J_DEF(regex),
		/**
		 * DateOption
		 * 设备端要求的日期类型<br>
		 * <ul>
		 * <li> 0: default:date and time(日期+时间)</li>
		 * <li> 1: date only(只要日期)</li>
		 *  <li>2: time only(只要时间)</li>
		 *  <li>3:date and time(日期+时间)</li>
		 *  </ul>
		 */
		__J_DEF(fieldRequire),
		/** FloatOption 显示精度:小数点位数,默认未定义 */
		__J_DEF(precision),
		/** BaseListOption 可选项列表 */
		__J_DEF(options),
		/** ImageOption 图像宽度 */
		__J_DEF(width),
		/** ImageOption 图像高度 */
		__J_DEF(height),
		/** ImageOption 图像格式 */
		__J_DEF(suffix)
	};
	//************************************
	// 返回JField对应的字段名
	// @param    JField id
	// @return   const std::string&
	//************************************
	static const std::string& name_of(JField id)
	{
#define __J_ENTRY(name) {_jf_##name, #name}
		static std::map<JField, std::string> fieldNames = {
			__J_ENTRY(name),
			__J_ENTRY(uiName),
			__J_ENTRY(path),
			__J_ENTRY(disable),
			__J_ENTRY(hide),
			__J_ENTRY(description),
			__J_ENTRY(container),
			__J_ENTRY(catalog),
			__J_ENTRY(childs),
			__J_ENTRY(canceled),
			__J_ENTRY(type),
			__J_ENTRY(value),
			__J_ENTRY(defaultValue),
			__J_ENTRY(required),
			__J_ENTRY(readOnly),
			__J_ENTRY(needReset),
			__J_ENTRY(available),
			__J_ENTRY(regex),
			__J_ENTRY(fieldRequire),
			__J_ENTRY(precision),
			__J_ENTRY(options),
			__J_ENTRY(width),
			__J_ENTRY(height),
			__J_ENTRY(suffix)
		};
#undef  __J_ENTRY
		assert(fieldNames.count(id));
		return fieldNames[id];
	}

	/**
	 * 条目特性开关
	 */
	enum item_features {
		/** 当前条目是否禁用(所有条目适用) */
		F_DISABLE = 0x000004,
		/** 当前条目是否在UI界面中隐藏(所有条目适用) */
		F_HIDE = 0x000008,
		/** 该选项是否为必须的(Option 适用) */
		F_REQUIRED = 0x000010,
		/** 该选项是否为只读的(Option 适用) */
		F_READONLY = 0x000020,
		/** 修改此选项值时会不会导致应用重启(Option 适用) */
		F_NEEDRESET = 0x000040
	};
	/** fieldRequire 字段默认值 */
	static const int DEFAULT_FIELDREQUIRE = 3;
	/** precision 字段默认值 */
	static const int DEFAULT_PRECISION = 3;
	struct BaseItem;
	struct BaseOption;
	struct CmdItem;
	struct MenuItem;
	using item_ptr_type = std::shared_ptr<BaseItem>;
	using items_type = tsl::ordered_map<std::string, item_ptr_type>;
	using option_ptr_type = std::shared_ptr<BaseOption>;
	using cmd_ptr_type = std::shared_ptr<CmdItem>;
	using menu_ptr_type = std::shared_ptr<MenuItem>;
	struct DeviceInstruction;
	using instruction_ptr = std::shared_ptr<DeviceInstruction>;
	struct ICmdInteractiveStatusListener;
	using cmd_status_listener_ptr = std::shared_ptr<ICmdInteractiveStatusListener>;

	item_ptr_type from_json(const dtalk::json &j);
	/**
	 * OPTION 值改变观察者类(侦听器)
	 * 当值改变时通知侦听器
	 */
	template<typename T>
	struct ValueObserver : public observable::observer
	{
		using value_listener_type = std::function<void(const T&)>;
		value_listener_type tmpl_listener;
		ValueObserver(const value_listener_type& tmpl_listener) :tmpl_listener(tmpl_listener) {}

		/** 后置实现  */
		virtual void update(const observable::observable &, const std::shared_ptr<void>& arg)override final;		
	};

	template<typename T>
	std::shared_ptr<T> cast_ptr(const std::shared_ptr<void> & ptr)
	{
		return std::static_pointer_cast<T>(ptr);
	}
	template<typename T>
	void release_ptr(std::shared_ptr<void> & ptr)
	{
		std::shared_ptr<void>swapptr;
		ptr.swap(swapptr);
		cast_ptr<T>(swapptr).reset();
	}
	template<typename T>
	typename std::enable_if<std::is_base_of<BaseItem, T>::value, item_ptr_type>::type
	asItemPtr(std::shared_ptr<T> & ptr){
		return cast_ptr<BaseItem>(ptr);
	}
	template<typename T, typename ...Args>
	typename std::enable_if<std::is_base_of<BaseItem, T>::value, item_ptr_type>::type
	make_item_shared(Args...args) {
		auto ptr = std::make_shared<T>(args...);
		ptr->init();
		return cast_ptr<BaseItem>(ptr);
	}
	template<typename T = MenuItem, typename ...Args>
	typename std::enable_if<std::is_base_of<MenuItem, T>::value, menu_ptr_type>::type
	make_menu_shared(Args...args) {
		auto ptr = std::make_shared<T>(args...);
		ptr->init();
		return cast_ptr<MenuItem>(ptr);
	}

	template<typename T, typename ...Args>
	typename std::enable_if<std::is_base_of<BaseOption, T>::value, option_ptr_type>::type
	make_option_shared(Args...args) {
		auto ptr = std::make_shared<T>(args...);
		ptr->init();
		return cast_ptr<BaseOption>(ptr);
	}
	/**
	* 返回枚举类型变量的名字字符串
	* 枚举类型 E 必须支持 nlohmann::json 的名字序列化和返序列
	*/
	template<typename E>
	const std::string& name_of(E e)
	{
		return json_utilits::name_of(e, dtalk::json());
	}
	/** 返回指定特性是否打开 */
	inline bool checkFeature(int feature, item_features f) {
		return f == (f & feature);
	}
	/** 设备命令执行状态 */
	enum Status {
		/** 设备命令成功执行完成 */
		ACK_OK,
		/** 设备端不支持的操作 */
		ACK_UNSUPPORTED,
		/** 调用出错 */
		ACK_ERROR,
		/** 设备命令响应超时 */
		ACK_TIMEOUT,
		/** 设备命令被拒绝执行 */
		ACK_REJECTED,
		/** 设备命令开始执行 */
		ACK_ACCEPTED,
		/** 返回设备命令完成进度 */
		ACK_PROGRESS,
		/** 执行中的设备命令被取消 */
		ACK_CANCELED
	};
	NLOHMANN_JSON_SERIALIZE_ENUM(Status, {
		__E_ENTRY(ACK_,OK),
		__E_ENTRY(ACK_,UNSUPPORTED),
		__E_ENTRY(ACK_,ERROR),
		__E_ENTRY(ACK_,TIMEOUT),
		__E_ENTRY(ACK_,REJECTED),
		__E_ENTRY(ACK_,ACCEPTED),
		__E_ENTRY(ACK_,PROGRESS),
		__E_ENTRY(ACK_,CANCELED)
	})
	enum HowtodoPredefineType {
		/** 保存数据为本地文件 */HTD_SAVE,
		/** 以适当的方式显示数据 */	HTD_SHOW
	};
	NLOHMANN_JSON_SERIALIZE_ENUM(HowtodoPredefineType, {
		__E_ENTRY(HTD_,SAVE),__E_ENTRY(HTD_,SHOW)
	})
		/**
		 * 设备命令请求类型
		 *
		 */
		enum ReqCmdType {
		/**  1对1命令 */DRQ_DEFAULT,
		/** 1对多的广播命令 */DRQ_MULTI,
		/** 任务队列 */DRQ_TASKQUEUE
	};
	NLOHMANN_JSON_SERIALIZE_ENUM(ReqCmdType, {
		__E_ENTRY(DRQ_,DEFAULT),__E_ENTRY(DRQ_,MULTI),__E_ENTRY(DRQ_,TASKQUEUE)
	})
		struct FormatedValue {
		/** 响应对象的原始数据 */
		dtalk::json value;
		/** MIME格式表示的数据类型  */
		std::string contentType;
		/** 希望前端处理处理的方式,参见{@link HowtodoPredefineType}预定义类型 */
		HowtodoPredefineType howtodo;
	};
	struct Ack {
		int cmdSn;
		int deviceId;
		std::string deviceMac;
		std::string item;
		dtalk::json value;
		std::string valueType;
		HowtodoPredefineType howtodo;
		Status status;
		std::string statusMessage;
		std::string exception;
		std::string trace;
		void setValue(const FormatedValue& fmtValue)
		{
			value = fmtValue.value;
			valueType = fmtValue.contentType;
			howtodo = fmtValue.howtodo;
		}
		_BASIC_JSON_TPL_DECLARATION_
			void setValue(const _BASIC_JSON_TPL_&j)
		{
			this->value = j;
		}
		template<typename T>
		void setValue(const T&value)
		{
			setValue(dtalk::json(value));
		}
		/**
		 * @return 返回状态信息
		 */
		std::string message() {
			auto buffer = gdface::string_utils::format("device%d@%d:%s", deviceId, cmdSn, name_of(status).c_str());
			switch (status) {
			case ACK_ERROR:
			case ACK_REJECTED:
				if (!statusMessage.empty()) {
					buffer = buffer.append(":").append(statusMessage);
				}
				break;
			case ACK_PROGRESS:
				/** 此状态下value字段如果为数字类型则被解释为完成进度(0-100) */
				if (value.type() == nlohmann::detail::value_t::number_integer
					|| value.type() == nlohmann::detail::value_t::number_unsigned
					|| value.type() == nlohmann::detail::value_t::number_float) {
					buffer = buffer.append(":finished %").append(std::to_string(value.get<int>()));
				}
				if (!statusMessage.empty()) {
					buffer = buffer.append(":").append(statusMessage);
				}
				break;
			case ACK_TIMEOUT:
			case ACK_UNSUPPORTED:
			case ACK_OK:
			case ACK_ACCEPTED:
			case ACK_CANCELED:
			default:
				break;
			}
			return buffer;
		}
		void writeError(const std::exception &e)
		{
			status = Status::ACK_ERROR;
			statusMessage = e.what();
			exception = typeid(e).name();
		}
		dtalk::json to_json()const
		{
			dtalk::json j;
			j["cmdSn"] = cmdSn;
			j["deviceId"] = deviceId;
			j["deviceMac"] = deviceMac;
			j["item"] = item;
			j["value"] = value;
			j["valueType"] = valueType;
			j["howtodo"] = howtodo;
			j["status"] = status;
			j["statusMessage"] = statusMessage;
			j["exception"] = exception;
			j["trace"] = trace;
			return std::move(j);
		}
		_BASIC_JSON_TPL_DECLARATION_
		void from_json(const _BASIC_JSON_TPL_ & j)
		{
			json_utilits::fill_field(cmdSn, j, "cmdSn");
			json_utilits::fill_field(deviceId, j, "deviceId");
			json_utilits::fill_field(deviceMac, j, "deviceMac");
			json_utilits::fill_field(item, j, "item");
			json_utilits::fill_field(value, j, "value");
			json_utilits::fill_field(valueType, j, "valueType");
			json_utilits::fill_field(howtodo, j, "howtodo");
			json_utilits::fill_field(status, j, "status");
			json_utilits::fill_field(statusMessage, j, "statusMessage");
			json_utilits::fill_field(exception, j, "exception");
			json_utilits::fill_field(trace, j, "trace");
			json_utilits::fill_field(cmdSn, j, "cmdSn");
		}
		std::string to_string() {
			return to_json().dump(4);
		}
	};
	_BASIC_JSON_TPL_DECLARATION_
	void to_json(_BASIC_JSON_TPL_ & j, const Ack & ack)
	{
		j = ack.to_json();
	}
	_BASIC_JSON_TPL_DECLARATION_
	void from_json(const _BASIC_JSON_TPL_ & j, Ack & ack)
	{
		ack.from_json(j);
	}

	/**
	 * 设备信息访问接口<br>
	 * SDK初始化时以SPI(Service Provider Interface)机制加载应用层提供的
	 * {@link DeviceInfoProvider}实例,并通过接口实例获取设备信息<br>
	 */
	struct DeviceInfoProvider {
		virtual ~DeviceInfoProvider() = default;
		/**
		 * 应用层通过此方法向底层提供管理密码
		 * @return 返回管理密码,不可为空或{@code null}
		 */
		virtual std::string getPassword() = 0;
		/**
		 * 保存在管理密码.<br>
		 * 应用层通过此方法保存底层传回的管理密码
		 * @param password 密码
		 */
		virtual void savePassword(const std::string &password) {}
		/** 返回当前使用的网卡mac地址(6字节二进制数据),不可为空或{@code null} */
		virtual std::string getMac() = 0;
		/** 返回16进制格式的MAC地址字符串，such as '58fb842d2953' */
		virtual std::string getMacAsString() {	return gdface::format_mac(getMac(),"");}
		/** 返回当前使用的IP地址(4字节二进制数据),不可为空或{@code null} */
		virtual std::string getIp() = 0;
		/** 返回'.'号分隔十进制格式的IP地址字符串，such as '192.168.1.100' */
		virtual std::string getIpAsString() {return gdface::format_ip(getIp());};
	};
	using dev_info_ptr = std::shared_ptr<DeviceInfoProvider>;
	/**
	 * 命令状态侦听器，用于交互命令向管理端发送命令执行状态
	 */
	struct ICmdInteractiveStatusListener {
		virtual ~ICmdInteractiveStatusListener() = default;
		/**
		 * 返回设备命令完成进度<br>
		 * 设备命令在执行过程中应该定时调用此方法，以作为心跳发送给管理端，直到任务结束
		 * @param progress 完成进度(0-100),可为{@code null}
		 * @param statusMessage 附加状态消息,可为{@code null}
		 */
		virtual void onProgress(int progress, const std::string &statusMessage) = 0;
		/**
		 * 任务结束,设备命令成功执行完成
		 * @param value 命令执行返回值,没有返回值则为{@code null}
		 */
		virtual void onFinished(const dtalk::json &value) = 0;
		/**
		 * 任务结束,执行中的设备命令被取消
		 */
		virtual void onCaneled() = 0;
		/**
		 * 任务结束,调用抛出异常
		 * @param errorMessage 错误信息，可为{@code null}
		 * @param error 异常对象，可为{@code null}
		 */
		virtual void onError(std::string errorMessage, const std::exception &error) = 0;
		/** 超时处理 */
		virtual void onTimeout() = 0;
		/**
		 * 此方法用于设备命令发送方控制设备端定时报告进度的间隔(秒)，
		 * 设备端调用此方法获取数值后，用于控制调用{@link #onProgress(Integer, std::string)}方法的调用间隔
		 * @return 返回要求的{@link #onProgress(Integer, std::string)}方法调用间隔(秒)，{@code <=0}时，使用设备自定义的默认值
		 */
		virtual int getProgressInternal() = 0;
		/** 返回上一次调用 onProgress 函数的系统时间 */
		virtual date::time_mills getLastProgress() = 0;
		/**
		 * 初始化当前对象
		 * @param ack 要设置的 ack
		 * @return 返回当前对象
		 */
		virtual cmd_status_listener_ptr init(const Ack& ack) = 0;
	};

	/**
	 * 设备命令数据<br>
	 * 此类对象将做为设备命令经redis服务器发送到设备端,
	 * 数据发到redis服务器以及设备端从redis服务器收到数据的过程要经过JSON序列化和反序列化<br>
	 *
	 */
	struct DeviceInstruction : public std::enable_shared_from_this<DeviceInstruction>
	{
		std::string cmdpath;
		int cmdSn;
		std::vector<int> target;
		bool group;
		std::string ackChannel;
		dtalk::json parameters;
		virtual ~DeviceInstruction() = default;
		/**
		 * 指定设备命令的目标ID及目标类型(设备/设备组)
		 * @param target 目标设备列表
		 * @param group 目标是否为设备组
		 * @return 当前对象
		 */
		instruction_ptr setTarget(const std::vector<int> &target, bool group) {
			this->target = target;
			this->group = group;
			return shared_from_this();
		}
		/**
		 * 设置设备命令参数
		 * @param key 参数名
		 * @param value 参数值
		 * @return 当前对象
		 */
		template<typename T>
		instruction_ptr withParameters(std::string key, const T &value) {
			this->parameters[key] =  value;
			return shared_from_this();
		}
		dtalk::json to_json()const
		{
			dtalk::json j;
			j["cmdpath"] = cmdpath;
			j["cmdSn"] = cmdSn;
			j["target"] = target;
			j["group"] = group;
			j["ackChannel"] = ackChannel;
			j["parameters"] = parameters;
			return std::move(j);
		}
		_BASIC_JSON_TPL_DECLARATION_
		void from_json(const _BASIC_JSON_TPL_ & j)
		{
			json_utilits::fill_field(cmdpath, j, "cmdpath");
			json_utilits::fill_field(cmdSn, j, "cmdSn");
			json_utilits::fill_field(target, j, "target");
			json_utilits::fill_field(group, j, "group");
			json_utilits::fill_field(ackChannel, j, "ackChannel");
			json_utilits::fill_field(parameters, j, "parameters");
		}
	};
	_BASIC_JSON_TPL_DECLARATION_
	void to_json(_BASIC_JSON_TPL_ & j, const DeviceInstruction & ins)
	{
		j = ins.to_json();
	}
	_BASIC_JSON_TPL_DECLARATION_
	void from_json(const _BASIC_JSON_TPL_ & j, DeviceInstruction & ins)
	{
		ins.from_json(j);
	}
	/** 命令执行接口 */
	struct ICmdUnionAdapter{
		virtual bool isInteractive() = 0;
		virtual ~ICmdUnionAdapter() = default;
	};
	using adapter_ptr = std::shared_ptr<ICmdUnionAdapter>;
	/**
	 * 立即执行设备命令执行接口
	 */
	struct ICmdImmediateAdapter :public virtual ICmdUnionAdapter 
	{
		virtual ~ICmdImmediateAdapter() = default;
		bool isInteractive() override final { return false; }
		/**
		 * 执行设备命令
		 * @param input 以值对(key-value)形式提供的输入参数
		 * @return 命令返回值，没有返回值则返回{@code null}
		 * @throws CmdExecutionException 命令执行失败
		 */
		virtual dtalk::json apply(const std::map<std::string,std::string> & input) = 0;
	};
	/**
	 * 交互设备命令接口
	 */
	struct ICmdInteractiveAdapter : public virtual ICmdUnionAdapter
	{
		virtual ~ICmdInteractiveAdapter() = default;
		bool isInteractive() override final { return true; }
		/**
		 * 执行设备命令
		 * @param input 以值对(key-value)形式提供的输入参数
		 * @param listener 状态侦听器，用于向管理端发送命令状态
		 * @throws InteractiveCmdStartException 当设备命令被拒绝或不支持或其他出错时抛出此异常,通过{@link InteractiveCmdStartException#getStatus() }获取状态类型
		 */
		virtual void apply(const dtalk::json & input, const std::shared_ptr<ICmdInteractiveStatusListener> &listener)=0;
		/**
		 * 取消当前执行的设备命令
		 * @throws UnsupportedOperationException 设备命令不支持取消
		 */
		virtual void cancel() = 0;
	};

	/**
	 * 菜单选项抽象类
	 * 所有选项的基类
	 */
	struct BaseItem : public std::enable_shared_from_this<BaseItem>{
		item_ptr_type parent;
		BaseItem(
			const std::string &name = "",
			const std::string &uiName = "",
			const std::string &path = "",
			const std::string &description = "",
			int features = 0,
			const item_ptr_type &parent = nullptr) : parent(parent)
		{
			fields[__J_NAME(name)] = name;
			fields[__J_NAME(uiName)] = uiName;
			fields[__J_NAME(path)] = path;
			fields[__J_NAME(disable)] = checkFeature(features, F_DISABLE);
			fields[__J_NAME(hide)] = checkFeature(features, F_HIDE);
			fields[__J_NAME(description)] = description;
		}
		BaseItem(
			const dtalk::json &fields,
			const item_ptr_type &parent = nullptr) : fields(fields), parent(parent)
		{
			/** 检查参数合法性,必须包含 container,catalog 字段 */
			throw_except_if_msg(std::invalid_argument, !fields.contains(__J_NAME(container)),
				gdface::log::sample_format("'container'field NOT FOUND in JSON"));
			throw_except_if_msg(std::invalid_argument, !fields.contains(__J_NAME(catalog)),
				gdface::log::sample_format("'catalog'field NOT FOUND in JSON"));
		}
		virtual void init() {}
		//************************************
		// 返回当前条目是否为容器,允许包含子条目
		//************************************
		bool isContainer() const
		{
			auto v = getField<bool>(_jf_container);
			throw_except_if_msg(std::logic_error, nullptr == v, "not define 'container' field");
			return *v;
		}
		//************************************
		// 返回当前条目的类型
		//************************************
		ItemType getCatalog() const
		{
			auto v = getField<ItemType>(_jf_catalog);
			throw_except_if_msg(std::logic_error, nullptr == v, "not define 'catalog' field");
			return *v;
		}
		virtual ~BaseItem() = default;
		//************************************
		// 根据字段名返回对应的值
		// @param    const std::string & name
		// @return 字段不存在或不是T类型则抛出异常
		//************************************
		template<typename T>
		T getFieldChecked(const std::string & name)const {
			auto v =  getField<T>(name);
			throw_except_if_msg(std::logic_error, nullptr == v, gdface::string_utils::format("not define '%s' field",name));
			return *v;
		}
		//************************************
		// 根据字段ID返回对应的值
		// @param    Field id
		// @return 字段不存在或不是T类型则抛出异常
		//************************************
		template<typename T>
		T getFieldChecked(JField id)const {
			return getFieldChecked<T>(name_of(id));
		}
		// 根据字段名返回对应的值
		// @param    const std::string & name
		// @param    const T & defaultValue
		// @return 字段不存在则返回默认值
		//************************************
		template<typename T>
		T getField(const std::string & name, const T& defaultValue)const {
			try
			{
				if (fields.contains(name))
				{
					return fields[name].get<T>();
				}
			}
			catch (const std::exception&)
			{
			}
			return defaultValue;
		}
		//************************************
		// 根据字段ID返回对应的值
		// @param    Field id
		// @param    const T & defaultValue
		// @return 字段不存在则返回默认值
		//************************************
		template<typename T>
		T getField(JField id, const T& defaultValue)const {
			return getField<T>(name_of(id),defaultValue);
		}
		//************************************
		// 根据字段名返回对应的值
		// @param    const std::string & name
		// @return 字段不存在则返回null
		//************************************
		template<typename T>
		std::shared_ptr<T> getField(const std::string & name)const {
			try
			{
				if (fields.contains(name))
				{
					return std::make_shared<T>(fields[name].get<T>());
				}
			}
			catch (const std::exception&)
			{
			}			
			return nullptr;
		}
		//************************************
		// 根据字段ID返回对应的值
		// @param    Field id
		// @return 字段不存在则返回null
		//************************************
		template<typename T>
		std::shared_ptr<T> getField(JField id)const {
			return getField<T>(name_of(id));
		}
		//************************************
		// 根据字段名返回对应的字符串类型的值
		// @param    const std::string & name
		// @return 字段不存在则则抛出异常
		//************************************
		std::string getStringFieldChecked(const std::string & name)const
		{
			return getFieldChecked<std::string>(name);
		}
		//************************************
		// 根据字段名返回对应的字符串类型的值
		// @param    JField id
		// @return 字段不存在则抛出异常
		//************************************
		std::string getStringFieldChecked(JField id)const
		{
			return getFieldChecked<std::string>(id);
		}
		//************************************
		// 根据字段名返回对应的字符串类型的值
		// @param    const std::string & name
		// @return 字段不存在则返回空
		//************************************
		std::string getStringField(const std::string & name)const
		{
			auto v = getField<std::string>(name);
			return v ? *v : "";
		}
		//************************************
		// 根据字段名返回对应的字符串类型的值
		// @param    JField id
		// @return 字段不存在则返回空
		//************************************
		std::string getStringField(JField id)const
		{
			return getStringField(name_of(id));
		}
		//************************************
		// 对指定字段赋值
		// @param    const std::string & name
		// @param    const T & value
		// @return   dtalk::BaseItem& 当前对象
		//************************************
		template<typename T>
		item_ptr_type setField(const std::string & name, const T& value) {
			throw_except_if_msg(std::invalid_argument, name.empty(), "name is empty");
			/* 检查原有值是否为T类型 */
			if (fields.contains(name)) 
			{
				try
				{
					/** 检查原有值是否为T类型,如果存在值,尝试转为T,原有值类型不为T,会抛出 type_error 异常 */
					auto old = fields[name].get<T>();
				}
				catch (const nlohmann::detail::type_error & e) {
					throw std::logic_error(std::string("type of value mismatch with last type:") + e.what());
				}
			}
			fields[name] = value;
			return shared_from_this();
		}
		//************************************
		// 对指定字段赋值
		// @param    Field id
		// @param    const T & value
		// @return   dtalk::BaseItem& 当前对象
		//************************************
		template<typename T>
		item_ptr_type setField(JField id, const T& value) {
			return setField(name_of(id),value);
		}
		//************************************
		// 对指定字段赋值(字符串)
		// @param    const std::string & name
		// @param    const std::string & value
		// @return   dtalk::BaseItem& 当前对象
		//************************************
		item_ptr_type setStringField(const std::string & name, const std::string& value)
		{
			return setField<std::string>(name, value);
		}
		//************************************
		// 对指定字段赋值(字符串)
		// @param    JField id
		// @param    const std::string & value
		// @return   dtalk::BaseItem& 当前对象
		//************************************
		item_ptr_type setStringField(JField id, const std::string& value)
		{
			return setStringField(name_of(id), value);
		}
		std::string getName() const
		{
			auto v = getField<std::string>(name_of(_jf_name));
			return v ? *v : "";
		}
		std::string getUiName() const
		{
			auto v = getField<std::string>(name_of(_jf_uiName));
			return v ? *v : "";
		}
		std::string getUiNameOrName() const {

			auto v = getUiName();
			return v.empty() ? getName() : v;
		}
		bool isDisable()const 
		{
			return getField<bool>(_jf_disable, false);
		}
		/** 返回指定的节点作为当前对象的子节点所处位置的索引值,如果非子节点返回-1 */
		int indexOf(const BaseItem *child) const {
			if (child) {
				auto found = std::find_if(items.begin(), items.end(),
					[&](const std::pair<std::string, item_ptr_type>&p) {
					return p.second.get() == child;
				});
				if (found == items.end()) {
					return -1;
				}
				return (int)std::distance(items.begin(), found);
			}
			return -1;
		}
		/** 指定的节点是否为当前对象的子节点 */
		bool isChild(const BaseItem *child) const { return indexOf(child) >= 0; }
		//************************************
		// 设置父结点
		// @param    const item_ptr_type & parent 父结点
		// @return   dtalk::BaseItem& 当前对象
		//************************************
		BaseItem& setParent(const item_ptr_type &parent)
		{
			throw_except_if_msg(std::invalid_argument, !parent, "parent is null");
			throw_except_if_msg(std::invalid_argument, !parent->isContainer(), "parent must be container");
			throw_except_if_msg(std::invalid_argument, parent->isChild(this), gdface::log::sample_format("DUPLICATE element in parent for name [{}]", getName()));

			this->parent = parent;
			checkCycleRef();
			refreshPath();
			return *this;
		}
		virtual void refreshPath() {
			setStringField(_jf_path, createPath(false));
			std::for_each(items.begin(), items.end(),
				[](const std::pair<std::string, item_ptr_type>&p) {
				p.second->refreshPath();
			});
		}
		std::string getPath()
		{
			auto path = getField<std::string>(_jf_path);
			if (!path || path->empty())
			{
				refreshPath();
			}
			return getStringFieldChecked(_jf_path);
		}
		//************************************
		// 添加子条目,如果元素已经存在则跳过
		// @param    InputIt first 起始迭代器
		// @param    InputIt last 终止迭代器
		// @return   dtalk::BaseItem& 当前对象
		//************************************
		template<typename InputIt>
		item_ptr_type addChilds(InputIt first, InputIt last)
		{
			if (isContainer()) {
				std::for_each(first, last, [&](const item_ptr_type &child) {
					if (child) {
						if (!items.count(child->getName())) {
							child->setParent(shared_from_this());
							items[child->getName()] = child;
						}
					}
				});
			}
			return shared_from_this();
		}
		//************************************
		// 添加子条目,如果元素已经存在则跳过
		// @param    const C & c 容器对象
		// @return   BaseItem& 当前对象
		//************************************
		template<typename C,
			typename InputIt = typename C::const_iterator,
			typename S = typename InputIt::value_type,
			typename T = typename S::element_type>
		typename std::enable_if<std::is_base_of<BaseItem,T>::value, item_ptr_type>::type
		addChilds(const C& c)
		{
			return addChilds(c.begin(), c.end());
		}
		//************************************
		// 添加子条目,如果元素已经存在则跳过
		// @param    std::initializer_list<item_ptr_type> childs 子条目列表
		// @return   item_ptr_type 当前对象
		//************************************
		item_ptr_type addChilds(std::initializer_list<item_ptr_type> childs)
		{
			return addChilds(childs.begin(), childs.end());
		}
		//************************************
		// 在index指定索引位置添加子条目,如果元素已经存在则跳过
		// @param    int index 索引位置，越界则默认为最后位置，当前子条目数量为0时忽略此值
		// @param    const item_ptr_type & child 子条目对象
		// @return   item_ptr_type 当前对象
		//************************************
		item_ptr_type addChild(int index, const item_ptr_type &child)
		{
			throw_except_if_msg(std::invalid_argument, !child, "child is null");

			if (!items.count(child->getName()))
			{
				if (index >= items.size() || index < 0 || items.empty())
				{
					child->setParent(shared_from_this());
					items.emplace(child->getName(), child);
				}
				else
				{
					int c = 0;
					auto itor = items.begin();
					while (c < index) ++itor;
					child->setParent(shared_from_this());
					items.insert(itor, std::make_pair(child->getName(), child));
				}
			}
			return shared_from_this();
		}
		//************************************
		// 在添加子条目到未尾,如果元素已经存在则跳过
		// @param    const item_ptr_type & child 子条目对象
		// @return   item_ptr_type 当前对象
		//************************************
		item_ptr_type addChild(const item_ptr_type &child)
		{
			return addChilds({ child });
		}
		//************************************
		// 在index指定索引位置添加子条目,如果元素已经存在则跳过
		// @param    int index 索引位置，越界则默认为最后位置，当前子条目数量为0时忽略此值
		// @param    const B & child 子条目对象
		// @return   BaseItem& 当前对象
		//************************************
		template<typename B>
		typename std::enable_if<std::is_base_of<BaseItem, B>::value, item_ptr_type>::type
		addChild(int index, const B &child)
		{
			return addChild(index, std::make_shared<B>(child));
		}
		//************************************
		// @return   size_t 返回子条目的数量
		//************************************
		size_t childCount() const { return items.size(); }
		//************************************
		// 根据index指定的子条目索引查找当前对象下的子条目
		// @return   dtalk::json 子条目，没找到返回nullptr
		//************************************
		dtalk::json childNames()const
		{
			dtalk::json m;
			std::for_each(items.begin(), items.end(), [&](const std::pair<std::string, item_ptr_type>& p) {
				std::string k = p.first;
				std::string v = p.second->getStringField(_jf_path);
				m[k] = v;
			});
			return std::move(m);
		}
		std::vector<item_ptr_type> getChilds()const {
			std::vector<item_ptr_type> v;
			std::for_each(items.begin(), items.end(), [&](const std::pair<std::string, item_ptr_type>& p) {
				v.emplace_back(p.second);
			});
			return std::move(v);
		}
		//************************************
		// 根据index指定的子条目索引查找当前对象下的子条目<br>
		// @param    int index 子条目索引
		// @return   dtalk::item_ptr_type 子条目，没找到返回nullptr
		//************************************
		item_ptr_type getChild(int index)const
		{
			if (index >= 0 && index < items.size())
			{
				auto itor = items.begin();
				while (index -- > 0)++itor;
				return itor->second;
			}
			return nullptr;
		}
		//************************************
		// 根据name指定的条目名称查找当前对象下的子条目
		// 如果name为数字则为子条目索引
		// @param    const std::string & name 条目名称
		// @return   dtalk::item_ptr_type 子条目，没找到返回nullptr
		//************************************
		/**
		* 根据{@code name}指定的条目名称查找当前对象下的子条目<br>
		* 如果{@code name}为数字则为子条目索引
		* @param name 条目名称
		* @return 子条目，没找到返回{@code null}
		*/
		item_ptr_type getChild(const std::string &name)const
		{
			try
			{
				return items.at(name);
			}
			catch (const std::out_of_range&)
			{
				try
				{
					return getChild(std::stoi(name));
				}
				catch (const std::exception &) {}
			}
			return nullptr;

		}
		/**
		 * 返回{@code path}指定的路径查找当前对象下的子条目<br>
		 * @param path 菜单条目路径
		 * @return 返回子条目，没有找到返回{@code null}
		 */
		item_ptr_type getChildByPath(const std::string &path) {
			std::string relpath = path;
			if (gdface::start_with(path,"/")) {
				if (gdface::start_with(path,getPath())) {
					relpath = path.substr(getPath().length());
				}
				else {
					std::string inxpath = createPath(true);
					if (gdface::start_with(path,inxpath)) {
						relpath = path.substr(inxpath.length());
					}
					else {
						return nullptr;
					}
				}
			}
			if (relpath.empty()) {
				return nullptr;
			}
			if (gdface::start_with(relpath,"/")) {
				relpath = relpath.substr(1);
			}
			if (gdface::end_with(relpath,"/")) {
				relpath = relpath.substr(0, relpath.length() - 1);
			}
			auto nodes = gdface::split(relpath,"/");
			auto child = shared_from_this();
			for (std::string node : nodes) {
				child = child->getChild(node);
				if (!child) {
					return nullptr;
				}
			}
			return child;
		}
		/**
		 * 根据{@code path}指定的路径查找对象,
		 * 先在当前对象中查找，如果找不到，从根结点查找
		 * @param path 菜单条目路径
		 * @return 返回找到的{@link BaseItem},找不到返回{@code null}
		 */
		item_ptr_type find(const std::string &path) {
			// 当前对象查找
			auto child = getChildByPath(path);
			if (child) {
				return child;
			}
			auto root = shared_from_this();
			for (; root->parent != nullptr; root = root->parent) {}
			// 从根菜单查找
			return root->getPath() ==path ? shared_from_this() : root->getChildByPath(path);
		}
		/**
		 * 根据{@code path}指定的路径查找对象,
		 * 与{@link #find(String)}基本相同,只是当找不到指定的对象时抛出异常
		 * @param path 菜单条目路径
		 * @return 返回找到的{@link BaseItem}对象
		 * @throws IllegalArgumentException 没找到指定的对象
		 */
		item_ptr_type findChecked(const std::string &path) {
			auto item = find(path);
			throw_if_msg(!item, gdface::string_utils::format("NOT FOUND ITEM [%s]", path.c_str()));
			return item;
		}
		template<typename T>
		typename std::enable_if<std::is_base_of<BaseItem, T>::value, std::shared_ptr<T>>::type
		as() {
			auto ptr = std::dynamic_pointer_cast<T>(shared_from_this());
			throw_if_msg(nullptr ==ptr,gdface::string_utils::format("FAILT TO CAST POINTER %s", typeid(T).name()));
			return ptr;
		}
		//************************************
		// @return   dtalk::json 当前对象的对应的 json 对象
		//************************************
		dtalk::json toJson() const
		{
			dtalk::json j;
			to_json(j);
			return j;
		}
		virtual void to_json(dtalk::json & j) const
		{
			j = fields;
			if (items.empty())
			{
				j[__J_NAME(childs)] = dtalk::json();
			}
			else {
				/** childs 字段以数组形式输出 */
				j[__J_NAME(childs)] = getChilds();
			}
		}
		virtual void from_json(const dtalk::json & j)
		{
			reset();
			fields = j;
			if (j.contains(__J_NAME(childs))) {
				auto childs = j[__J_NAME(childs)];
				std::for_each(childs.begin(), childs.end(), [&](const dtalk::json &v) {
					auto p = dtalk::from_json(v);
					if (p)
					{
						items[p->getName()] = p;
					}
				});
			}
		}
		void from_json(const std::string & j)
		{
			if (!j.empty()) {
				from_json(dtalk::json::parse(j));
			}
		}
		void from_json(const char* j)
		{
			if (j)
			{
				from_json(std::string(j));
			}
		}
	protected:
		//************************************
		// 检查循环引用, 如果为循环引用则抛出异常
		//************************************
		/**
		* 检查循环引用, 如果为循环引用则抛出异常
		*/
		void checkCycleRef()const
		{
			auto node = this;
			while (node->parent)
			{
				/** 检查参数合法性 */
				throw_except_if_msg(std::invalid_argument, node->parent.get() == this,
					gdface::log::sample_format(" CYCLE REFERENCE "));
				node = node->parent.get();
			}
		}
		//************************************
		// 当前对象数据清除复位
		//************************************
		virtual void reset()
		{
			fields = dtalk::json();
			items = items_type();
		}
		observable::observable obs;
	public:
		/** 保存所有需要序列化的字段 */  
		dtalk::json fields;
		items_type items;
	private:
		//************************************
		// 生成能对象在菜单中全路径名
		// @param    bool indexInstead 是否用索引值代替名字
		// @return   std::string 全路径名
		//************************************
		std::string createPath(bool indexInstead) {
			std::list<std::string> list;
			for (auto item = this; item->parent; item = item->parent.get()) {
				if (indexInstead) {
					list.emplace_back(std::to_string(parent->indexOf(item)));
				}
				else {
					list.emplace_back(item->getName());
				}
			}
			list.reverse();
			return std::string("/").append(std::join_to_string(list, "/"));
		}
		friend item_ptr_type from_json(const dtalk::json &j);
		friend void from_json(const dtalk::json &j, item_ptr_type &item);
		friend void to_json(dtalk::json &j, const item_ptr_type &item);		
	};

#define DEF_ITEM_CTOR(_c, _b, _t,_a) \
		_c( \
			const std::string &name = "", \
			const std::string &uiName = "", \
			const std::string &path = "", \
			const std::string &description = "", \
			int features = 0, \
			const item_ptr_type &parent = nullptr) :_b(name, uiName, path, description, features, parent) {\
			fields[__J_NAME(container)] = _a; \
			fields[__J_NAME(catalog)] = _t; \
		} \
		_c( \
			const dtalk::json &fields, \
			const item_ptr_type &parent = nullptr) : _b(fields, parent) { \
			this->fields[__J_NAME(container)] = _a; \
			this->fields[__J_NAME(catalog)] = _t; \
		}

	struct BaseOption : public BaseItem {
		using value_ptr_type = dtalk::json;
		using available_type = dtalk::json;
		/** 选项值合法性验证函数定义 */
		using validator_type = std::function<bool(const dtalk::json&)>;

		OptionType getType() const
		{
			return getFieldChecked<OptionType>(_jf_type);
		}
		virtual std::string contentOfValue()const
		{
			return getOptionValue().is_null() ? "" : getOptionValue().dump();
		}
		BaseOption(
			const OptionType &type,
			const std::string &name = "",
			const std::string &uiName = "",
			const std::string &path = "",
			const std::string &description = "" ,
			int features = 0,			
			const value_ptr_type &optionValue = dtalk::json(), 
			const value_ptr_type &defaultValue = dtalk::json(),
			const item_ptr_type &parent = nullptr)
			: BaseItem(name, uiName, path, description, features, parent), canNotify(true)
		{
			fields[__J_NAME(type)] = type;
			auto rx = pattern_of(type);
			if(!rx.empty())
			{
				fields[__J_NAME(regex)] = rx;
			}
			fields[__J_NAME(container)] = false;
			fields[__J_NAME(catalog)] = ItemType::DIT_OPTION;
			fields[__J_NAME(value)] = optionValue;
			fields[__J_NAME(defaultValue)] = defaultValue;
			fields[__J_NAME(required)] = checkFeature(features, F_REQUIRED);
			fields[__J_NAME(readOnly)] = checkFeature(features, F_READONLY);
			fields[__J_NAME(needReset)] = checkFeature(features, F_NEEDRESET);
		}
		BaseOption(
			const dtalk::json &fields,
			const item_ptr_type &parent = nullptr) : BaseItem(fields, parent), canNotify(true)
		{
			throw_if_msg(fields.contains(__J_NAME(type)), std::string(__J_NAME(type)) + "NOT DEFINED");
			this->fields[__J_NAME(container)] = false;
			this->fields[__J_NAME(catalog)] = ItemType::DIT_OPTION;
			if (!fields.contains(__J_NAME(regex)))
			{
				auto type = fields[__J_NAME(type)].get<OptionType>();
				auto rx = pattern_of(type);
				if (!rx.empty())
				{
					this->fields[__J_NAME(regex)] = rx;
				}
			}
		}
		virtual ~BaseOption() = default;
		virtual void init() override
		{
			BaseItem::init();
			this->canNotify = false;
			/** 对于string类型的值调用asValue检查格式是否匹配 */
			if (fields[__J_NAME(value)].is_string())
			{
				auto s = fields[__J_NAME(value)].get<std::string>();
				if (!s.empty())
				{
					asValue(fields[__J_NAME(value)].get<std::string>());
				}
			}
			if (fields[__J_NAME(defaultValue)].is_string())
			{
				auto s = fields[__J_NAME(defaultValue)].get<std::string>();
				if (!s.empty())
				{
					asValue(fields[__J_NAME(defaultValue)].get<std::string>());
				}
			}
			this->canNotify = true;
		}
		template<typename T>
		BaseOption& addAvailable(std::initializer_list<T> av)
		{
			if (hasAvaiable())
			{
				if (!fields.contains(name_of(_jf_available)))
				{
					fields[name_of(_jf_available)] = tsl::ordered_set<T>();
				}
				auto &available = fields[name_of(_jf_available)];
				std::for_each(av.begin(), av.end(), [&](const T&t) {
					available.insert(available.end(), dtalk::json(t));
				});
			}
			return *this;
		}
		template<typename T>
		BaseOption&	removeAvailable(std::initializer_list<T> avs)
		{
			if (hasAvaiable() && fields.contains(name_of(_jf_available)))
			{			
				auto available = fields[name_of(_jf_available)];
				auto v = available.get_ptr<dtalk::json::array_t*>();
				if (v)
				{
					std::for_each(avs.begin(), avs.end(), [&](const T&t) {
						v->erase(std::remove(v->begin(), v->end(), dtalk::json(t)),v->end());
						});
				}
			}
			return *this;
		}
		BaseOption& setValidator(const validator_type& validator)
		{
			this->valueValidator = validator;
			return *this;
		}
		template<typename T>
		option_ptr_type setValue(const T& optionValue)
		{
			setValue(dtalk::json(optionValue));
			return std::static_pointer_cast<BaseOption>(shared_from_this());
		}
		option_ptr_type setValue(const dtalk::json & optionValue)
		{
			fields[__J_NAME(value)] = optionValue;
			if (canNotify && obs.countObservers()) {
				obs.notifyObservers(shared_from_this());
			}
			return std::static_pointer_cast<BaseOption>(shared_from_this());
		}
		virtual option_ptr_type asValue(const std::string &optionValue)
		{
			checkStringValue(optionValue);
			setValue<std::string>(optionValue);
			return std::static_pointer_cast<BaseOption>(shared_from_this());
		}
		//************************************
		// 检查字符串是否匹配当前类型的格式,不匹配则抛出异常
		// @param    const std::string & value
		//************************************
		void checkStringValue(const std::string& value)const
		{
			auto _type = getType();
			auto &pattern = pattern_of(_type);
			if (!pattern.empty())
			{
				/** 检查参数合法性 */
				throw_if_msg(!std::regex_match(value, std::regex(pattern)),
					gdface::log::sample_format("INVALID FORMAT '{}' FOR {}", value, name_of(_type)))
			}
		}
		template<typename T>
		std::shared_ptr<T> getValue()const
		{
			std::shared_ptr<T> v;
			auto value = this->getOptionValue();
			if (!value.is_null())
			{
				v = std::make_shared<T>(value.get<T>());
			}
			return v;
		}
		template<typename T>
		std::shared_ptr<T> getDefaultValue()const
		{
			std::shared_ptr<T> v;
			dtalk::json defaultValue = this->getDefaultValue();
			if (!defaultValue.is_null())
			{
				v = std::make_shared<T>(defaultValue.get<T>());
			}
			return v;
		}
		/**
		 * @return 返回选项的值，如果为null则返回默认值
		 */
		dtalk::json fetch() const 
		{
			if (getOptionValue().is_null()) {
				return getDefaultValue();
			}
			return getOptionValue();
		}
		//************************************
		// 更新value字段
		// @param    const dtalk::json & value
		//************************************
		void updateFrom(const dtalk::json& value)
		{
			throw_except_if_msg(std::logic_error, getFieldChecked<bool>(_jf_readOnly), "READONLY VALUE");
			throw_if_msg(!valueValidator(value), "INVALID VALUE");
			setValue(value);
		}
		void updateFrom(const option_ptr_type req)
		{
			if (req) {
				// 设置参数
				updateFrom(req->getOptionValue());
			}
		}
		//************************************
		// 添加值改变侦听器
		// @param    const std::function<void(const T&)>& listener 侦听函数,为nullptr忽略
		// @return   option_ptr_type 当前对象
		//************************************
		template<typename T>
		option_ptr_type addListener(const std::function<void(const T&)>& listener)
		{
			if (listener) {
				obs.addObserver(std::make_shared<ValueObserver<T>>(listener));
			}
			return as<BaseOption>();
		}
		virtual void from_json(const dtalk::json & j)override
		{
			BaseItem::from_json(j);
			/** 检查参数合法性 */
			throw_if_msg(!j.contains(__J_NAME(type)),
				gdface::log::sample_format("'type'field NOT FOUND in JSON"));
		}
	protected:
		dtalk::json getOptionValue()const
		{
			return fields.contains(__J_NAME(value)) ? fields[__J_NAME(value)] : dtalk::json();
		}
		dtalk::json getDefaultValue()const
		{
			return fields.contains(__J_NAME(getDefaultValue)) ? fields[__J_NAME(getDefaultValue)] : dtalk::json();
		}
		dtalk::json& getOptionValue()
		{
			static dtalk::json nulljson;
			return fields.contains(__J_NAME(value)) ? fields[__J_NAME(value)] : nulljson;
		}
		dtalk::json& getDefaultValue()
		{
			static dtalk::json nulljson;
			return fields.contains(__J_NAME(getDefaultValue)) ? fields[__J_NAME(getDefaultValue)] : nulljson;
		}
		/** 是否执行通知 */
		bool canNotify;
	private:
		bool hasAvaiable()
		{
			auto type = getType();
			return type != OptionType::DOP_BASE64
				&& type != OptionType::DOP_MULTICHECK
				&& type != OptionType::DOP_IMAGE
				&& type != OptionType::DOP_BASE64
				&& type != OptionType::DOP_INTEGER
				&& type != OptionType::DOP_PASSWORD;
		}
		validator_type valueValidator = [](const dtalk::json&t) { return true; };
	};

	/** 因为 ValueObserver::update 引用到了BaseOption的函数,需要后置实现 */
	template<typename T>
	void ValueObserver<T>::update(const observable::observable &, const std::shared_ptr<void>& arg)
	{
		if (arg)
		{
			auto opt = std::static_pointer_cast<BaseOption>(arg);
			auto v = opt->getValue<T>();
			if (v && tmpl_listener)
			{
				tmpl_listener(static_cast<const T&>(*v));
			}
		}
	}
	struct BaseBinary : public BaseOption {
		using BaseOption::BaseOption;
		virtual ~BaseBinary() = default;
		virtual std::string contentOfValue() const override
		{
			if (!this->getOptionValue().is_string()) {
				return BaseOption::contentOfValue();
			}
			auto v = getOptionValue().get<std::string>();
			if (v.size() == 0)
			{
				return BaseOption::contentOfValue();
			}
			if (v.size() <= 32) {
				/** 转为十六进制(HEX)字符串 */
				return gdface::bytes_to_hex_string(v.data(), v.size());
			}
			/** 过长的数据就不显示完整内容 */
			return gdface::fold(v, 32);

		}
		virtual void to_json(dtalk::json & j) const override
		{
			BaseOption::to_json(j);
			if (!getOptionValue().is_null()) {
				j[__J_NAME(value)] = json_utilits::to_base64(getOptionValue());
			}
			if (!getDefaultValue().is_null()) {
				j[__J_NAME(defaultValue)] = json_utilits::to_base64(getDefaultValue());
			}
		}
		virtual void from_json(const dtalk::json & j)override
		{
			BaseOption::from_json(j);
			json_utilits::from_base64(getOptionValue());
			json_utilits::from_base64(getDefaultValue());
		}
	protected:
	};

#define DEF_OPTION_CTOR(_c,_b,_t) \
	_c( \
		const std::string &name, \
		const std::string &uiName, \
		const std::string &path, \
		const std::string &description = "", \
		int features = 0, \
		const value_ptr_type &optionValue = dtalk::json(), \
		const value_ptr_type &defaultValue = dtalk::json(), \
		const item_ptr_type &parent = nullptr, \
		const OptionType type = _t) \
		: _b(_t, name, uiName, path, description, features, optionValue, defaultValue, parent){}\
	_c( \
		const dtalk::json &fields, \
		const item_ptr_type &parent = nullptr) : _b(fields, parent) {}\
	_c( \
		const std::string &name = "", \
		const std::string &uiName = "", \
		const std::string &path = "", \
		const std::string &description = "", \
		int features = 0, \
		const std::string &optionValue = "", \
		const std::string &defaultValue = "", \
		const item_ptr_type &parent = nullptr, \
		const OptionType type = _t) \
		: _c(name, uiName, path, description, features, !optionValue.empty()? dtalk::json(optionValue):dtalk::json(), !defaultValue.empty()? dtalk::json(defaultValue):dtalk::json(), parent, _t){}\
	_c( \
		const char* name, \
		const char* uiName, \
		const char* path, \
		const char* description, \
		int features = 0, \
		const char* optionValue = nullptr, \
		const char* defaultValue = nullptr, \
		const item_ptr_type &parent = nullptr, \
		const OptionType type = _t) \
		: _c(name ? std::string(name):std::string(""), uiName ? std::string(uiName):std::string(""), path ? std::string(path):std::string(""), description ? std::string(description):std::string(""), features, optionValue ? std::string(optionValue):std::string(""), defaultValue ? std::string(defaultValue):std::string(""), parent, _t){}


#define DEF_OPTION_CTOR2(_c,_b,_t) \
	_c( \
		const std::string &name, \
		const std::string &uiName, \
		const std::string &path, \
		const std::string &description, \
		int features = 0, \
		const value_ptr_type &optionValue = dtalk::json(), \
		const value_ptr_type &defaultValue = dtalk::json(), \
		const item_ptr_type &parent = nullptr) \
		: _b(name, uiName, path, description, features, optionValue, defaultValue, parent, _t){}\
	_c( \
		const dtalk::json &fields, \
		const item_ptr_type &parent = nullptr) : _b(fields, parent) {\
	} \
	_c( \
		const std::string &name = "", \
		const std::string &uiName = "", \
		const std::string &path = "", \
		const std::string &description = "", \
		int features = 0, \
		const std::string &optionValue = "", \
		const std::string &defaultValue = "",\
		const item_ptr_type &parent = nullptr) \
		: _b(name, uiName, path, description, features, !optionValue.empty()? dtalk::json(optionValue):dtalk::json(), !defaultValue.empty()? dtalk::json(defaultValue):dtalk::json(), parent, _t){}\
	_c( \
		const char* name, \
		const char* uiName, \
		const char* path, \
		const char*description, \
		int features = 0, \
		const char* optionValue = nullptr, \
		const char* defaultValue = nullptr,\
		const item_ptr_type &parent = nullptr ) \
		: _b(name ? std::string(name):std::string(""), uiName ? std::string(uiName):std::string(""), path ? std::string(path):std::string(""), description ? std::string(description):std::string(""), features, optionValue ? std::string(optionValue):std::string(""), defaultValue ? std::string(defaultValue):std::string(""), parent, _t){}

	struct Base64Option : public BaseBinary {
		DEF_OPTION_CTOR(Base64Option, BaseBinary, OptionType::DOP_BASE64)
		virtual option_ptr_type asValue(const std::string &optionValue) override
		{
			if (!optionValue.empty())
			{
				auto bin = gdface::hex_to_bytes(optionValue);
				setValue<std::string>(std::string((char*)bin.data(), bin.size()));
			}
			return std::static_pointer_cast<BaseOption>(shared_from_this());
		}
	};
	struct ImageOption : public BaseBinary {
		DEF_OPTION_CTOR(ImageOption, BaseBinary, OptionType::DOP_IMAGE)
		virtual std::string contentOfValue() const override
		{
			auto v = getValue<std::string>();
			return gdface::log::sample_format("{}({}x{}),size={}", getStringField(_jf_suffix), getField<int>(_jf_width, 0), getField<int>(_jf_height, 0), v ? 0 : v->size());
		}
		virtual option_ptr_type asValue(const std::string &optionValue) override
		{
			if (!optionValue.empty())
			{
				auto bin = gdface::hex_to_bytes(optionValue);
				setValue<std::string>(std::string((char*)bin.data(), bin.size()));
			}
			return std::static_pointer_cast<BaseOption>(shared_from_this());
		}
	};
	struct IPv4Option : public BaseBinary {
		DEF_OPTION_CTOR(IPv4Option, BaseBinary, OptionType::DOP_IP)
		virtual std::string contentOfValue()const
		{

			if (!getOptionValue().is_string()) {
				return BaseBinary::contentOfValue();
			}
			auto v = getOptionValue().get<std::string>();
			assert(v.size() == 4);
			return gdface::format_ip(v);
		}
		virtual option_ptr_type asValue(const std::string &optionValue) override
		{
			auto parsed = gdface::parse_ip(optionValue);
			if (!parsed.empty())
			{
				setValue<std::string>(parsed);
			}
			return std::static_pointer_cast<BaseOption>(shared_from_this());
		}
	};
	struct MACOption : public BaseBinary {
		DEF_OPTION_CTOR(MACOption, BaseBinary, OptionType::DOP_MAC)
		virtual std::string contentOfValue()const
		{
			if (!getOptionValue().is_string()) {
				return BaseBinary::contentOfValue();
			}
			auto v = getOptionValue().get<std::string>();
			return gdface::format_mac(v);
		}
		virtual option_ptr_type asValue(const std::string &optionValue) override
		{
			auto parsed = gdface::parse_mac(optionValue);
			if (!parsed.empty())
			{
				setValue<std::string>(parsed);
			}
			return std::static_pointer_cast<BaseOption>(shared_from_this());
		}
	};
	struct BaseNumOption : public BaseOption {
		using BaseOption::BaseOption;
	};

	struct FloatOption : public BaseNumOption {
		DEF_OPTION_CTOR(FloatOption, BaseNumOption, OptionType::DOP_FLOAT)
		virtual option_ptr_type asValue(const std::string &optionValue) override
		{
			auto v = gdface::parse_float(optionValue);
			if (v)
			{
				setValue<double>(dtalk::json(*v));
			}
			return std::static_pointer_cast<BaseOption>(shared_from_this());
		}
		FloatOption& setPrecision(int precision)
		{
			if (precision >= 0) {
				setField<int>(_jf_precision, precision);
			}
			return *this;
		}
		virtual void to_json(dtalk::json & j) const override
		{
			BaseOption::to_json(j);
			if (!fields.contains(__J_NAME(precision)))
			{
				j[__J_NAME(precision)] = DEFAULT_PRECISION;
			}
		}
	};
	struct IntOption : public BaseNumOption {
		DEF_OPTION_CTOR(IntOption, BaseNumOption, OptionType::DOP_INTEGER)
		virtual option_ptr_type asValue(const std::string &optionValue) override
		{
			auto v = gdface::parse_int(optionValue);
			if (v)
			{
				setValue<int>(*v);
			}
			return std::static_pointer_cast<BaseOption>(shared_from_this());
		}
	};
	struct BoolOption : BaseOption {
		DEF_OPTION_CTOR(BoolOption, BaseOption, OptionType::DOP_BOOL)
		virtual option_ptr_type asValue(const std::string &optionValue) override
		{
			auto v = gdface::parse_bool(optionValue);
			if (v)
			{
				setValue<bool>(*v);
			}
			return std::static_pointer_cast<BaseOption>(shared_from_this());
		}
	};

	struct BaseListOption : public BaseOption {
		using BaseOption::BaseOption;
		//************************************
		// 添加可选项
		// @param    const T & opt 可选项的值
		// @param    const std::string & desc 可选项描述
		// @return   dtalk::BaseListOption & 当前对象
		//************************************
		template<typename T>
		std::shared_ptr<BaseListOption> addOption(const T &opt, const std::string &desc = "") {
			auto s = std::to_string(opt);
			optionsValues[s] = opt;
			fields[__J_NAME(options)][s] = desc;
			return std::static_pointer_cast<BaseListOption>(shared_from_this());
		}
		//************************************
		// 以字符串形式输出所有可选项内容
		// @return   std::string
		//************************************
		std::string contentOfOptions()const
		{
			std::stringstream ss;
			ss << "\tavailable options:\n";
			int index = 0;
			if (fields.contains(__J_NAME(options)))
			{
				dtalk::json optionsdesc = fields[__J_NAME(options)];
				for (auto& el : optionsdesc.items()) {
					auto v = el.value();
					auto desc = v.is_null() ? "" : v.get<std::string>();
					ss << "\t<" << index++ << ">" << el.key() << " -- " << (desc.empty() ? "NO DESC" : desc) << std::endl;
				}
			}
			return ss.str();
		}

	protected:
		//************************************
		// @return  从options(json)中返回所有可选值列表
		//************************************
		template<typename T>
		void initOptionsValues(T* /* unused */)const
		{
			if (0 == optionsValues.size() && fields.contains(__J_NAME(options)))
			{
				dtalk::json optionsdesc = fields[__J_NAME(options)];
				for (auto& el : optionsdesc.items()) 
				{
					auto t = dtalk::json::parse(el.key());
					optionsValues[el.key()] = t;
				}
			}
		}
		void initOptionsValues(std::string* /* unused */)const
		{
			if (0 == optionsValues.size() && fields.contains(__J_NAME(options)))
			{
				dtalk::json optionsdesc = fields[__J_NAME(options)];
				for (auto& el : optionsdesc.items())
				{
					optionsValues[el.key()] = el.key();
				}
			}
		}
		//************************************
		// @return  从options(json)中返回所有可选值列表
		//************************************
		template<typename T>
		std::vector<T> optValues()const
		{
			initOptionsValues((T*)nullptr);
			std::vector<T> opts;
			std::transform(optionsValues.begin(), optionsValues.end(), std::back_inserter(opts), [](const dtalk::json &p) { return p.get<T>(); });
			return opts;
		}

		/* 保存可选项 */
		mutable dtalk::json optionsValues;
	};
	
	struct CheckOption : public BaseListOption {
		DEF_OPTION_CTOR(CheckOption, BaseListOption, OptionType::DOP_MULTICHECK)
		template<typename T>
		std::list<T> getSelected() const
		{
			std::list<T> sel;
			auto value = getOptionValue();
			if (!value.is_null()) {
				auto opts = this->template optValues<T>();
				std::transform(value.begin(), value.end(), std::back_inserter(sel), [&](int c) {
					return opts[c];
				});
			}
			return sel;
		}
		template<typename T>
		CheckOption& setSelected(const std::list<T> &selects)
		{
			if (!selects.empty())
			{
				auto opts = this->template optValues<T>();
				std::set<int> v;
				std::for_each(selects.begin(), selects.end(), [&](const T& t) {
					auto result = std::find(opts.begin(), opts.end(), t);
					if (result != opts.end())
					{
						v.insert((int)std::distance(opts.begin(), result));
					}
				});
				if (!v.empty())
				{
					fields[__J_NAME(value)] = v;
				}
			}
			return *this;
		}
		template<typename It>
		CheckOption& setValue(It first,It last) 
		{
			std::vector<int> v(first, last);
			auto sp = std::remove_if(v.begin(), v.end(), [&](const int &idx) {return idx >= optionsValues.size(); });
			if (sp != v.begin())
			{
				fields[__J_NAME(value)] = std::make_shared<std::set<int>>(v.begin(), sp);
			}
			return *this;
		}
		CheckOption& setValue(std::initializer_list<int> selects)
		{
			std::vector<int> v(selects);
			auto sp = std::remove_if(v.begin(), v.end(), [&](const int &idx) {return idx >= optionsValues.size(); });
			if (sp != v.begin())
			{
				fields[__J_NAME(value)] = std::make_shared<std::set<int>>(v.begin(), sp);
			}
			return *this;
		}
		virtual option_ptr_type asValue(const std::string &optionValue) override
		{
			auto v = gdface::parse_int_list(optionValue);
			if (v)
			{
				setValue(v->begin(), v->end());
			}
			return std::static_pointer_cast<BaseOption>(shared_from_this());
		}
	};

	struct SwitchOption : public BaseListOption {
		DEF_OPTION_CTOR(SwitchOption, BaseListOption, OptionType::DOP_SWITCH)
		template<typename T>
		value_ptr_type getSelected() const
		{
			value_ptr_type sel;
			int idx = -1;
			auto optionValue = this->template getField<int>(_jf_value);
			auto defaultValue = this->template getField<int>(_jf_defaultValue);
			if (optionValue)
			{
				idx = *optionValue;		
			} else if (defaultValue)
			{
				idx = *defaultValue;
			}
			auto opts = this->template optValues<T>();
			if (idx >= 0 && idx < opts.size())
			{
				sel = std::make_shared<T>(opts[idx]);
			}
			return sel;
		}
		template<typename T>
		SwitchOption& setSelected(const T &sel)
		{
			auto opts = this->template optValues<T>();
			int idx = 0;
			std::for_each(opts.begin(), opts.end(),[&](const T&t) {
				if (t == sel) {
					fields[__J_NAME(value)] = idx;
				}
				idx++;
			});
			return *this;
		}
		SwitchOption& setValue(int select)
		{
			if (select >= 0 && select < optionsValues.size())
			{
				fields[__J_NAME(value)] = std::make_shared<int>(select);
			}
			return *this;
		}
		virtual option_ptr_type asValue(const std::string &optionValue) override
		{
			auto v = gdface::parse_int(optionValue);
			if (v)
			{
				setValue(*v);
			}
			return std::static_pointer_cast<BaseOption>(shared_from_this());
		}

	};
	struct DateOption : public BaseOption {
		DEF_OPTION_CTOR(DateOption, BaseOption, OptionType::DOP_DATE)
		virtual option_ptr_type asValue(const std::string &optionValue) override
		{
			throw_if_msg(optionValue.empty(), "optionValue String is empty");
			date::time_mills mills;
			auto b = date::parse_uni_datetime(optionValue, mills);
			throw_if_msg(!b, gdface::log::sample_format("INVALID DATE FORMAT '{}' FOR {}", optionValue, name_of(getType())));
			setValue(dtalk::json(mills));
			return std::static_pointer_cast<BaseOption>(shared_from_this());
		}
		DateOption& setFieldRequire(int fieldRequire) {
			switch (fieldRequire & 3) {
			case 1:
			case 2:
				setField<int>(_jf_fieldRequire, fieldRequire);
				break;
			default:
				setField<int>(_jf_fieldRequire, DEFAULT_FIELDREQUIRE);
				break;
			}
			return *this;
		}
		virtual void to_json(dtalk::json & j) const override
		{
			BaseOption::to_json(j);
			if (!fields.contains(__J_NAME(fieldRequire)))
			{
				j[__J_NAME(fieldRequire)] = DEFAULT_FIELDREQUIRE;
			}
		}
	};
	struct StringOption : public BaseOption {
		DEF_OPTION_CTOR(StringOption, BaseOption, OptionType::DOP_STRING)
	};
	struct PasswordOption : public StringOption{
		DEF_OPTION_CTOR2(PasswordOption, StringOption, OptionType::DOP_PASSWORD)
		virtual std::string contentOfValue() const override 
		{

			auto value = getOptionValue();
			if (value.is_string())
			{
				auto v = value.get<std::string>();
				if (v.size() > 0) {
					return std::string(v.size(), '*');
				}
			}
			return "empty password";
		}
	};

	struct EmailOption : public StringOption {
		DEF_OPTION_CTOR2(EmailOption, StringOption, OptionType::DOP_EMAIL)
	};
	struct MphoneOption : public StringOption {
		DEF_OPTION_CTOR2(MphoneOption, StringOption, OptionType::DOP_MPHONE)
	};
	struct IdnumOption : public StringOption {
		DEF_OPTION_CTOR2(IdnumOption, StringOption, OptionType::DOP_IDNUM)
	};
	struct UrlOption : public BaseOption {
		DEF_OPTION_CTOR(UrlOption, BaseOption, OptionType::DOP_URL)
	};

	struct CmdItem : public BaseItem {
		DEF_ITEM_CTOR(CmdItem, BaseItem, ItemType::DIT_CMD, true)
	private:
		adapter_ptr cmdAdapter;
		std::mutex cmd_mtx;
		bool interactive;
	public:
		virtual ~CmdItem() = default;
		std::vector<option_ptr_type> getParameters() const
		{
			std::vector<option_ptr_type> v;
			auto childs = getChilds();
			std::transform(childs.begin(), childs.end(), std::back_inserter(v),
				[](const item_ptr_type& item) {return item->as<BaseOption>(); });
			return v;
		}
		template<typename InputIt>
		void addParameters(InputIt first, InputIt last) {
			addChilds(first, last);
		}
		void addParameters(std::initializer_list<option_ptr_type> parameters)
		{
			addParameters(parameters.begin(), parameters.end());
		}
		void setParameters(std::initializer_list<option_ptr_type> parameters) {
			items.clear();
			addParameters(parameters);
		}
		option_ptr_type getParameter(const std::string &name) const {
			return std::dynamic_pointer_cast<BaseOption>(getChild(name));
		}
		adapter_ptr getCmdAdapter() const {
			return cmdAdapter;
		}
		void setCmdAdapter(adapter_ptr cmdAdapter) {
			throw_if_msg(cmdAdapter && cmdAdapter->isInteractive() && !interactive, 
				gdface::string_utils::format("%s is immediate CMD,ICmdImmediateAdapter implementation required", getName().c_str())); 
			throw_if_msg(cmdAdapter && !cmdAdapter->isInteractive() && interactive,
				gdface::string_utils::format("%s is interactive CMD,ICmdInteractiveAdapter implementation required", getName().c_str())); 
			this->cmdAdapter = cmdAdapter;
		}
		void setInteractive(bool interactive)
		{
			this->interactive = interactive;
		}
		bool isInteractiveCmd() const
		{
			return interactive;
		}
		/**
		 * 更新命令参数
		 * @param parameters 命令参数
		 * @return 当前对象
		 */
		void updateParameter(const dtalk::json &parameters) {
			for (auto param : getParameters()) {
				auto name = param->getName();
				if (parameters.contains(name))
				{
					param->updateFrom(parameters[name]);
				}
			}
		}
		/**
		 * 参数 检查，如果参数为required,而输入参数中不包含这个参数，则抛出异常
		 * @param input
		 * @return input
		 */
		dtalk::json checkRequired(const dtalk::json& input) const {
			for (auto param : getParameters())
			{
				throw_if_msg(param->getFieldChecked<bool>(_jf_required) && !input.contains(param->getName()),
					gdface::string_utils::format("MISS REQUIRED PARAM %s", param->getName().c_str()));
			}
			return input;
		}
		/** 将参数值转为 名字-值映射的json */
		dtalk::json fetchValue()const
		{
			dtalk::json values;
			for (auto param : getParameters())
			{
				values[param->getName()] = param->fetch();
			}
			return values;
		}
		/**
		 * 设置所有参数为{@code null}
		 * @return 返回当前对象
		 */
		void reset() {
			for (auto item : getParameters()) {
				item->setValue(dtalk::json());
			}		
		}
		/**
		 * 执行立即命令
		 * @param parameters 命令参数
		 * @return 执行设备命令的返回结果对象
		 * @throws CmdExecutionException 设备命令执行异常
		 */
		dtalk::json runImmediateCmd(const dtalk::json& parameters) {
			throw_except_if_msg(std::logic_error, interactive,
				gdface::string_utils::format("%s is immediate CMD",getName().c_str()));
			if (cmdAdapter) {
				std::lock_guard<std::mutex> guard(cmd_mtx);
				updateParameter(parameters);
				gdface::raii _r(std::bind(&CmdItem::reset, this));				
				auto  objParams = fetchValue();
				auto adapter = std::dynamic_pointer_cast<ICmdImmediateAdapter>(cmdAdapter);
				return adapter->apply(checkRequired(objParams));

			}
			return dtalk::json();
		}

		/**
		 * 启动交互命令
		 * @param statusListener 设备命令状态侦听器
		 * @throws InteractiveCmdStartException 交互命令执行异常，当设备命令被拒绝或出错时抛出此异常
		 */
		void startInteractiveCmd(const cmd_status_listener_ptr& statusListener) {
			throw_except_if_msg(std::logic_error, !interactive,
				gdface::string_utils::format("%s is interactive CMD", getName().c_str()));
			if (cmdAdapter) {
				std::lock_guard<std::mutex> guard(cmd_mtx);
				gdface::raii _r(std::bind(&CmdItem::reset, this));
				auto  objParams = fetchValue();
				auto adapter = std::dynamic_pointer_cast<ICmdInteractiveAdapter>(cmdAdapter);
				adapter->apply(checkRequired(objParams),statusListener);
			}
		}
		/**
		 * 取消正在执行的交互命令
		 */
		void cancelInteractiveCmd() {
			throw_except_if_msg(std::logic_error, !interactive,
				gdface::string_utils::format("%s is interactive CMD", getName().c_str()));
			if(cmdAdapter)
			{
				auto adapter = std::dynamic_pointer_cast<ICmdInteractiveAdapter>(cmdAdapter);
				adapter->cancel();
			}
		}
	};
	struct MenuItem : public BaseItem {
		DEF_ITEM_CTOR(MenuItem, BaseItem, ItemType::DIT_MENU, true)
		virtual ~MenuItem() = default;
		/** 创建初始菜单时自动添加后退(返回上一级)选项 */
		virtual void init() override
		{
			BaseItem::init();
			items.clear();
			auto item = make_item_shared<CmdItem>();
			item->setField(_jf_name, BACK_NAME);
			// items[BACK_NAME] = item;/** 这是JAVA版本的逻辑,没有指定parent */
			addChilds({ item });/** Java 版的逻辑有问题,所以这里没有参照 Java 版本逻辑 */
		}
	};

	struct RootMenu : public MenuItem
	{
		RootMenu() :MenuItem() {}
		virtual void init() override {
			MenuItem::init();
			items.erase(BACK_NAME);
			auto item = make_item_shared<CmdItem>();
			item->setField(_jf_name, QUIT_NAME);
			addChilds({ item });
		}
	};

	//////////////// JSON /////////////////

	inline item_ptr_type from_json(const dtalk::json &j)
	{
		item_ptr_type item;
		throw_except_if_msg(std::invalid_argument, !j.contains(__J_NAME(catalog)), "'catalog' field not found");

		ItemType catalog = j[__J_NAME(catalog)].get<ItemType>();
		switch (catalog)
		{
		case DIT_MENU:
			item = std::make_shared<MenuItem>();
			break;
		case DIT_CMD:
			item = std::make_shared<CmdItem>();
			break;
		case DIT_OPTION:
		{
			throw_except_if_msg(std::invalid_argument, !j.contains(__J_NAME(type)), "'type' field not found for OPTION");

			OptionType type = j[__J_NAME(type)].get<OptionType>();
			switch (type)
			{
			case dtalk::DOP_STRING:
				item = std::make_shared<StringOption>();
				break;
			case dtalk::DOP_INTEGER:
				item = std::make_shared<IntOption>();
				break;
			case dtalk::DOP_FLOAT:
				item = std::make_shared<FloatOption>();
				break;
			case dtalk::DOP_BOOL:
				item = std::make_shared<BoolOption>();
				break;
			case dtalk::DOP_DATE:
				item = std::make_shared<DateOption>();
				break;
			case dtalk::DOP_URL:
				item = std::make_shared<UrlOption>();
				break;
			case dtalk::DOP_PASSWORD:
				item = std::make_shared<PasswordOption>();
				break;
			case dtalk::DOP_EMAIL:
				item = std::make_shared<EmailOption>();
				break;
			case dtalk::DOP_MPHONE:
				item = std::make_shared<MphoneOption>();
				break;
			case dtalk::DOP_IDNUM:
				item = std::make_shared<IdnumOption>();
				break;
			case dtalk::DOP_BASE64:
				item = std::make_shared<Base64Option>();
				break;
			case dtalk::DOP_MAC:
				item = std::make_shared<MACOption>();
				break;
			case dtalk::DOP_IP:
				item = std::make_shared<IPv4Option>();
				break;
			case dtalk::DOP_IMAGE:
				item = std::make_shared<ImageOption>();
				break;
			case dtalk::DOP_MULTICHECK:
				item = std::make_shared<CheckOption>();
				break;
			case dtalk::DOP_SWITCH:
				item = std::make_shared<SwitchOption>();
				break;
			default:
				break;
			}
			break;
		}
		default:
			break;
		}
		if (item)
		{
			item->from_json(j);
		}

		return item;
	}
	inline item_ptr_type from_json(const std::string &j)
	{
		return from_json(j.empty() ? dtalk::json() : dtalk::json::parse(j));
	}
	inline item_ptr_type from_json(const char *j)
	{
		return from_json(j ? std::string(j) : "");

	}
	inline void from_json(const dtalk::json &j, item_ptr_type &item)
	{
		if (item)
		{
			*item = *from_json(j);
		}
		else {
			item = nullptr;
		}
	}
	inline void to_json(dtalk::json &j, const item_ptr_type &item)
	{
		if (item)
		{
			item->to_json(j);
		}
		else
		{
			j = dtalk::json();
		}
	}
	inline void from_json(const dtalk::json &j, BaseItem &item)
	{
		item = *from_json(j);
	}
	inline void to_json(dtalk::json &j, const BaseItem &item)
	{
		item.to_json(j);
	}
} /** namespace dtalk */
#endif /* DTALK_DTALK_ITEM_H_ */
